package com.java.common.boot.interceptor;

import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.java.common.boot.advice.BodyAdvice;
import com.java.common.boot.advice.BodyAdviceKit;
import com.java.common.constant.Constants;
import com.java.common.lang.annotation.FileData;
import com.java.common.lang.annotation.RichText;
import com.java.common.lang.annotation.ValidateToken;
import com.java.common.lang.domain.AjaxResult;
import com.java.common.lang.domain.ReturnVO;
import com.java.common.lang.domain.page.TableDataInfo;
import com.java.common.lang.exception.BaseException;
import com.java.common.service.PcTokenService;
import com.java.common.utils.WebKit;
import com.java.common.utils.html.HtmlKit;

/**
 * 前台用户token验证拦截器（PC端）
 * 
 * @author yilabao
 * @date 2021年6月3日
 */
public class PcTokenInterceptor implements AsyncHandlerInterceptor {

    private static final String LOGIN_HTML_URL = "/login.html?returnUrl=";

    private static final String DOT_HTML_SUFFIX = ".html";

    @Autowired
    private PcTokenService tokenSrv;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        HandlerMethod handlerMethod = (HandlerMethod) handler;

        boolean validateToken = isValidateToken(handlerMethod);

        if (!validateToken) {
            return true;
        }

        if (!tokenSrv.checkLogin(request)) {
            String location = WebKit.getLocation();
            if (!location.contains(DOT_HTML_SUFFIX)) {
                throw new BaseException("您还未登录，请先登录");
            }
            String loginLocation = WebKit.getBasePath() + LOGIN_HTML_URL + URLEncoder.encode(location, Constants.UTF8);
            response.sendRedirect(loginLocation);
            return false;
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        resetModel(modelAndView);
        AsyncHandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 重置Model对象（统一处理资源路径）
     * 
     * @author yilabao
     * @date 2021年9月15日
     * @param modelAndView
     * @throws Exception
     */
    private void resetModel(ModelAndView modelAndView) throws Exception {
        if (modelAndView == null) {
            return;
        }
        Set<Entry<String, Object>> modelSet = modelAndView.getModel().entrySet();
        if (modelSet.isEmpty()) {
            return;
        }
        final String basePath = WebKit.getFileBasePath();
        for (Entry<String, Object> entry : modelSet) {
            Object body = entry.getValue();
            if (body == null) {
                continue;
            }
            if (body instanceof BeanPropertyBindingResult) {
                continue;
            }
            Object dataBody = body;
            if (body instanceof AjaxResult) {
                dataBody = ((AjaxResult) body).getData();
            } else if (body instanceof ReturnVO) {
                dataBody = ((ReturnVO<?>) body).getData();
            } else if (body instanceof TableDataInfo) {
                dataBody = ((TableDataInfo) body).getRows();
            }
            BodyAdviceKit.resetComplexObject(dataBody, FileData.class, new BodyAdvice() {
                @Override
                public Object getAdviceFieldValue(Object fieldValue) throws Exception {
                    return HtmlKit.getFileHttpAllPath(String.valueOf(fieldValue), basePath);
                }
            });
            BodyAdviceKit.resetSimpleObject(dataBody, RichText.class, new BodyAdvice() {
                @Override
                public Object getAdviceFieldValue(Object fieldValue) throws Exception {
                    return HtmlKit.getHtmlContent(String.valueOf(fieldValue), basePath);
                }
            });
        }
    }

    /**
     * 是否需要验证登录
     * 
     * @author yilabao
     * @date 2021年1月28日
     * @param handlerMethod
     * @return boolean
     */
    private boolean isValidateToken(HandlerMethod handlerMethod) {
        ValidateToken validateToken = getValidateToken(handlerMethod);
        if (validateToken == null) {
            return true;
        }
        return validateToken.isValidate();
    }

    /**
     * 先获取方法注解，如果没有，再获取类注解
     * 
     * @author yilabao
     * @date 2021年1月28日
     * @param handlerMethod
     * @return ValidateToken
     */
    private ValidateToken getValidateToken(HandlerMethod handlerMethod) {
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(ValidateToken.class)) {
            return method.getAnnotation(ValidateToken.class);
        }
        Class<?> type = handlerMethod.getBeanType();
        if (type.isAnnotationPresent(ValidateToken.class)) {
            return type.getAnnotation(ValidateToken.class);
        }
        return null;
    }

}